// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:_fe_analyzer_shared/src/messages/severity.dart'
    show CfeSeverity;
import 'package:kernel/ast.dart';
import 'package:kernel/type_environment.dart' show TypeEnvironment;
import 'package:kernel/verifier.dart';

import '../codes/cfe_codes.dart'
    show
        LocatedMessage,
        Message,
        codeVerificationErrorOriginContext,
        noLength,
        codeInternalProblemVerificationError;
import '../base/compiler_context.dart' show CompilerContext;

List<LocatedMessage> verifyComponent(
  CompilerContext context,
  VerificationStage stage,
  Component component, {
  bool skipPlatform = false,
  bool Function(Library library)? librarySkipFilter,
}) {
  CfeVerificationErrorListener listener = new CfeVerificationErrorListener(
    context,
  );
  VerifyingVisitor verifier = new VerifyingVisitor(
    context.options.target,
    stage,
    skipPlatform: skipPlatform,
    librarySkipFilter: librarySkipFilter,
    listener: listener,
  );
  component.accept(verifier);
  return listener.errors;
}

class CfeVerificationErrorListener implements VerificationErrorListener {
  final CompilerContext compilerContext;
  List<LocatedMessage> errors = [];

  CfeVerificationErrorListener(this.compilerContext);

  @override
  // Coverage-ignore(suite): Not run.
  void reportError(
    String details, {
    required TreeNode? node,
    required Uri? problemUri,
    required int? problemOffset,
    required TreeNode? context,
    required TreeNode? origin,
  }) {
    Message message = codeInternalProblemVerificationError.withArgumentsOld(
      details,
    );
    LocatedMessage locatedMessage = problemUri != null
        ? message.withLocation(
            problemUri,
            problemOffset ?? TreeNode.noOffset,
            noLength,
          )
        : message.withoutLocation();
    List<LocatedMessage>? contextMessages;
    if (origin != null) {
      contextMessages = [
        codeVerificationErrorOriginContext.withLocation(
          origin.location!.file,
          origin.fileOffset,
          noLength,
        ),
      ];
    }
    compilerContext.report(
      locatedMessage,
      CfeSeverity.error,
      context: contextMessages,
    );
    errors.add(locatedMessage);
  }
}

void verifyGetStaticType(
  TypeEnvironment env,
  Component component, {
  bool skipPlatform = false,
}) {
  component.accept(new CfeVerifyGetStaticType(env, skipPlatform));
}

class CfeVerifyGetStaticType extends VerifyGetStaticType {
  final bool skipPlatform;

  CfeVerifyGetStaticType(TypeEnvironment env, this.skipPlatform) : super(env);

  @override
  void visitLibrary(Library node) {
    // 'dart:test' is used in the unit tests and isn't an actual part of the
    // platform.
    if (skipPlatform &&
        node.importUri.isScheme('dart') &&
        node.importUri.path != "test") {
      return;
    }

    super.visitLibrary(node);
  }
}
